package com.elh.jvm;

import cn.hutool.core.util.StrUtil;
import com.elh.jvm.constantpool.ConstantPool;

/**
 * @author liulei
 **/
public class ClassFile {

    private byte[] data;

    private ClassReader classReader;

    // 次版本号
    private int minorVersion;

    // 主版本号
    private int majorVersion;

    // 类访问标志
    private int accessFlag;

    // 类索引
    private int classNameIndex;

    // 父类索引
    private int superClassNameIndex;

    // 接口索引
    private int[] interfaceIndexes;

    private MemberInfo[] fields;

    private MemberInfo[] methods;

    private ConstantPool constantPool;

    public ClassFile(byte[] data) {
        classReader = new ClassReader(data);
        readAndCheckMagic();
        readAndCheckVersion();
        readConstantPool();
        readAccessFlag();
        readClassNameIndex();
        readSuperClassNameIndex();
        readInterfaceIndexes();
        readFields();
        readMethods();
    }



    /***
     * 检查魔数,确定这个文件是否可以被jvm接收
     *
     */
    private void readAndCheckMagic() {
        // 0xCAFEBABE
        String magic = this.classReader.nextU4ToHexString();
        if(StrUtil.equalsIgnoreCase("0xCAFEBABE",magic)){
            throw new ClassFormatError("magic!");
        }
    }

    /**
     * 检查class文件的版本号
     *
     */
    private void readAndCheckVersion(){
        this.minorVersion = this.classReader.nextU2ToInt();
        this.majorVersion = this.classReader.nextU2ToInt();
        if (this.majorVersion >= 46 && this.majorVersion <= 52 && this.minorVersion == 0) {
            return;
        }
        throw new UnsupportedClassVersionError();
    }

    private void readAccessFlag() {
        this.accessFlag = classReader.nextU2ToInt();
    }

    private void readConstantPool() {
        this.constantPool = new ConstantPool(this.classReader);
    }

    /**
     * 类名索引
     */
    private void readClassNameIndex() {
        classNameIndex = classReader.nextU2ToInt();
    }

    /**
     * 超类索引
     */
    private void readSuperClassNameIndex() {
        superClassNameIndex = classReader.nextU2ToInt();
    }

    /**
     * 接口索引
     *
     */
    private void readInterfaceIndexes() {
        interfaceIndexes = classReader.nextUint16s();
    }

    private void readFields() {
        fields = MemberInfo.readMembers(constantPool, classReader);
    }

    private void readMethods() {
        methods = MemberInfo.readMembers(constantPool, classReader);
    }
}
